// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 该文件实现了源代码的压缩编码
// 使用查找表的位置。

package src

// XPos是Pos的一种更紧凑的表示形式。
type XPos struct {
	index int32
	lico
}

// NoXPos是一个有效的未知位置。
var NoXPos XPos

// IsKnown报告位置p是否已知。
// XPos.IsKnown（）与对应的
// 位置。
func (p XPos) IsKnown() bool {
	return p.index != 0 || p.Line() != 0
}

// Before报告源中位置p是否在q之前。
// 对于具有不同基数的头寸，按基数索引排序。
func (p XPos) Before(q XPos) bool {
	n, m := p.index, q.index
	return n < m || n == m && p.lico < q.lico
}

// SameFile报告p和q是否在同一文件中的位置。
func (p XPos) SameFile(q XPos) bool {
	return p.index == q.index
}

// SameFinedLine报告p和q是否位于同一文件中的同一行上。
func (p XPos) SameFileAndLine(q XPos) bool {
	return p.index == q.index && p.lico.SameLine(q.lico)
}

// After报告源中的位置p是否在q之后。
// 对于具有不同基数的头寸，按基数索引排序。
func (p XPos) After(q XPos) bool {
	n, m := p.index, q.index
	return n > m || n == m && p.lico > q.lico
}

// WithNotStmt返回要用DWARF标记的相同位置，即\u stmt=0
func (p XPos) WithNotStmt() XPos {
	p.lico = p.lico.withNotStmt()
	return p
}

// WithDefaultStmt返回与Undeminated is_stmt相同的位置
func (p XPos) WithDefaultStmt() XPos {
	p.lico = p.lico.withDefaultStmt()
	return p
}

// WithIsStmt返回要标记为DWARF的相同位置，即ISSTMT=1
func (p XPos) WithIsStmt() XPos {
	p.lico = p.lico.withIsStmt()
	return p
}

// WithBogusLine返回与源代码记录的任何代码都不匹配的伪代码行。
// 它的用途是中断无限循环中的语句，以便调试器
// 不会无限循环等待行号更改。
// gdb选择不显示伪线；delve以抱怨的方式展示了它，但是
// 另一种行为是绞死。
func (p XPos) WithBogusLine() XPos {
	if p.index == 0 {
		// 见
		panic("Assigning a bogus line to XPos with no file will cause mysterious downstream failures.")
	}
	p.lico = makeBogusLico()
	return p
}

// WithXlogue返回相同的位置，但标记为侏儒函数序言/尾声
func (p XPos) WithXlogue(x PosXlogue) XPos {
	p.lico = p.lico.withXlogue(x)
	return p
}

// LineNumber返回行号“？”的字符串（如果行号未知）。
func (p XPos) LineNumber() string {
	if !p.IsKnown() {
		return "?"
	}
	return p.lico.lineNumber()
}

// FileIndex返回与
// 此源位置的文件。小是相对的；它可以是数千
// 很大，但不是几百万。
func (p XPos) FileIndex() int32 {
	return p.index
}

func (p XPos) LineNumberHTML() string {
	if !p.IsKnown() {
		return "?"
	}
	return p.lico.lineNumberHTML()
}

// AtColumn1返回相同的位置，但已移动到第1列。
func (p XPos) AtColumn1() XPos {
	p.lico = p.lico.atColumn1()
	return p
}

// PosTable跟踪Pos->XPos转换，反之亦然。
// 它的零值是一个随时可用的邮资。
type PosTable struct {
	baseList []*PosBase
	indexMap map[*PosBase]int
	nameMap  map[string]int // 将文件符号名称映射到调试信息的索引。
}

// XPos返回给定pos对应的XPO，
// 如有必要，将pos添加到t。
func (t *PosTable) XPos(pos Pos) XPos {
	m := t.indexMap
	if m == nil {
		// 创建新列表和映射，并用nil填充
		// 以使NoPos始终获得索引0。
		t.baseList = append(t.baseList, nil)
		m = map[*PosBase]int{nil: 0}
		t.indexMap = m
		t.nameMap = make(map[string]int)
	}
	i, ok := m[pos.base]
	if !ok {
		i = len(t.baseList)
		t.baseList = append(t.baseList, pos.base)
		t.indexMap[pos.base] = i
		if _, ok := t.nameMap[pos.base.symFilename]; !ok {
			t.nameMap[pos.base.symFilename] = len(t.nameMap)
		}
	}
	return XPos{int32(i), pos.lico}
}

// Pos返回给定p对应的Pos。
// 如果p不能通过t进行转换，则函数会崩溃。
func (t *PosTable) Pos(p XPos) Pos {
	var base *PosBase
	if p.index != 0 {
		base = t.baseList[p.index]
	}
	return Pos{base, p.lico}
}

// FileIndex返回PosTable中给定文件名（符号）的索引，如果找不到，则返回-1。
func (t *PosTable) FileIndex(filename string) int {
	if v, ok := t.nameMap[filename]; ok {
		return v
	}
	return -1
}

// FileTable返回用于构建此包的所有文件的一部分。
func (t *PosTable) FileTable() []string {
	// 创建全局包级文件索引的LUT。这张桌子是什么
	// 写入debug_lines头中时，文件[N]将被引用为
	// 调试行表中的N+1。
	fileLUT := make([]string, len(t.nameMap))
	for str, i := range t.nameMap {
		fileLUT[i] = str
	}
	return fileLUT
}
